package com.chenfan.mcn.service.impl;

import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chenfan.common.exception.BusinessException;
import com.chenfan.common.vo.UserVO;
import com.chenfan.mcn.clients.baseinfo.BaseCustomer;
import com.chenfan.mcn.clients.baseinfo.BaseCustomerDetailVO;
import com.chenfan.mcn.clients.baseinfo.BaseInfoClient;
import com.chenfan.mcn.clients.baseinfo.McnCustomerSearchDTO;
import com.chenfan.mcn.clients.privilege.PrivilegeClient;
import com.chenfan.mcn.clients.privilege.SUserVo;
import com.chenfan.mcn.config.UserVoContextHolder;
import com.chenfan.mcn.dao.CustomerTargetMapper;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.mcn.model.CustomerTarget;
import com.chenfan.mcn.model.McnPage;
import com.chenfan.mcn.model.dto.CustomerTargetDTO;
import com.chenfan.mcn.model.dto.CustomerTargetImportDTO;
import com.chenfan.mcn.model.dto.CustomerTargetOutputDTO;
import com.chenfan.mcn.model.dto.CustomerTargetSearchDTO;
import com.chenfan.mcn.model.vo.*;
import com.chenfan.mcn.service.CustomerTargetService;
import com.chenfan.mcn.utils.BusinessAssert;
import com.chenfan.mcn.extension.excel.ExcelUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 重点客户目标 服务实现类
 * </p>
 *
 * @author lizhejin
 * @since 2021-04-22
 */
@Service
public class CustomerTargetServiceImpl extends ServiceImpl<CustomerTargetMapper, CustomerTarget> implements CustomerTargetService {

    @Autowired
    private BaseInfoClient baseInfoClient;

    @Autowired
    private PrivilegeClient privilegeClient;

    @Autowired
    private RedisTemplate redisTemplate;

    private final String CUSTOMER_TARGET_PREFIX = "customer:target:";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer addTarget(List<CustomerTargetDTO> customerTargetList) {
        verifyInsertParam(customerTargetList);
        verifyTargetCount(customerTargetList);
        List<CustomerTarget> customerTargets = new ArrayList<>();
        for (CustomerTargetDTO customerTargetDTO : customerTargetList) {
            CustomerTarget customerTarget = new CustomerTarget();
            customerTarget.setQuarterCode(customerTargetDTO.getQuarterCode());
            customerTarget.setTargetAmount(customerTargetDTO.getTargetAmount());
            customerTarget.setTargetCustomerId(customerTargetDTO.getTargetCustomerId());
            customerTargets.add(customerTarget);
        }
        return baseMapper.insertBatch(customerTargets);
    }

    @Override
    public CustomerTargetDTO targetDetail(Long id) {
        CustomerTarget customerTarget = baseMapper.selectById(id);
        if (customerTarget == null) {
            throw new BusinessException(McnErrorCode.CUSTOMER_TARGET_NOT_EXIST);
        }
        CustomerTargetDTO customerTargetDTO = new CustomerTargetDTO();
        BeanUtils.copyProperties(customerTarget, customerTargetDTO);
        Map<Long, BaseCustomer> baseCustomerMap = baseInfoClient.getMcnCustomerByIds(Arrays.asList(customerTargetDTO.getTargetCustomerId())).getObj();
        if (baseCustomerMap.containsKey(customerTargetDTO.getTargetCustomerId())) {
            customerTargetDTO.setTargetCustomerName(baseCustomerMap.get(customerTargetDTO.getTargetCustomerId()).getCustomerNameC());
        }
        return customerTargetDTO;
    }

    @Override
    public Integer deleteTarget(Long id) {
        CustomerTarget customerTarget = baseMapper.selectById(id);
        if (customerTarget == null) {
            throw new BusinessException(McnErrorCode.CUSTOMER_TARGET_NOT_EXIST);
        }
        customerTarget.setIsDelete(1);
        int delete = baseMapper.updateById(customerTarget);
        return delete;
    }

    @Override
    public Integer updateTarget(CustomerTargetDTO customerTargetDTO) {
        CustomerTarget entity = baseMapper.selectById(customerTargetDTO.getId());
        BusinessAssert.notNull(entity, McnErrorCode.CUSTOMER_TARGET_NOT_EXIST);
        CustomerTarget udpateCustomerTarget = new CustomerTarget();
        udpateCustomerTarget.setId(entity.getId());
        udpateCustomerTarget.setTargetAmount(customerTargetDTO.getTargetAmount());
        return baseMapper.updateById(udpateCustomerTarget);
    }

    @Override
    public Page<CustomerTargetPageVO> customerTargetPage(McnPage<CustomerTargetPageVO> mcnPage, CustomerTargetSearchDTO customerTargetSearchDTO) {

        if (StrUtil.isBlank(customerTargetSearchDTO.getQuarterCode())) {
            throw new BusinessException(McnErrorCode.PLEASE_CHOOSE_QUARTER_CODE);
        }
        /**
         * 如果有客户名称和客户负责人名称的模糊筛选，则获取对应模糊查询结果的客户id集合
         */
        if (StrUtil.isNotBlank(customerTargetSearchDTO.getCustomerName()) || StrUtil.isNotBlank(customerTargetSearchDTO.getCustomerHeadName())) {
            McnCustomerSearchDTO mcnCustomerSearchDTO = new McnCustomerSearchDTO();
            mcnCustomerSearchDTO.setCustomerName(customerTargetSearchDTO.getCustomerName());
            mcnCustomerSearchDTO.setCustomerHeadName(customerTargetSearchDTO.getCustomerHeadName());
            List<BaseCustomer> customerList = baseInfoClient.searchMcnCustomer(mcnCustomerSearchDTO).getObj();
            if (CollectionUtil.isEmpty(customerList)) {
                return new Page<CustomerTargetPageVO>();
            }
            customerTargetSearchDTO.setCustomerIds(customerList.stream().map(BaseCustomer::getCustomerId).collect(Collectors.toList()));
        }
        customerTargetSearchDTO.setAlias("c.");
        Page<CustomerTargetPageVO> customerTargetPage = baseMapper.customerTargetPage(mcnPage, customerTargetSearchDTO);
        List<CustomerTargetPageVO> customerTargetList = customerTargetPage.getRecords();
        if (CollectionUtil.isNotEmpty(customerTargetList)) {
            /**
             * 查询客户信息
             */
            List<Long> customerIds = customerTargetList.stream().map(CustomerTargetPageVO::getTargetCustomerId).distinct().collect(Collectors.toList());
            Map<Long, BaseCustomer> baseCustomerMap = baseInfoClient.getMcnCustomerByIds(customerIds).getObj();
            for (CustomerTargetPageVO customerTarget : customerTargetList) {
                Long targetCustomerId = customerTarget.getTargetCustomerId();
                if (baseCustomerMap.containsKey(targetCustomerId)) {
                    BaseCustomer baseCustomer = baseCustomerMap.get(targetCustomerId);
                    customerTarget.setTargetCustomerName(baseCustomer.getCustomerNameC());
                    customerTarget.setCustomerHeadId(baseCustomer.getCustomerHeadId());
                    customerTarget.setCustomerHeadName(baseCustomer.getCustomerHeadName());
                }
            }

            /**
             * 查询客户负责人的部门信息
             */
            List<Long> customerHeadIds = customerTargetList.stream().map(CustomerTargetPageVO::getCustomerHeadId).distinct().collect(Collectors.toList());
            List<SUserVo> userHeandList = privilegeClient.getDepartmentByUserIds(customerHeadIds).getObj();
            Map<Long, SUserVo> userHeadMap = userHeandList.stream().collect(Collectors.toMap(SUserVo::getUserId, o -> o));
            for (CustomerTargetPageVO customerTarget : customerTargetList) {
                Long customerHeadId = customerTarget.getCustomerHeadId();
                if (userHeadMap.containsKey(customerHeadId)) {
                    SUserVo sUserVo = userHeadMap.get(customerHeadId);
                    customerTarget.setCustomerHeadDepartmentId(sUserVo.getDepartmentId());
                    customerTarget.setCustomerHeadDepartmentName(sUserVo.getDepartmentName());
                }
            }
        }
        return customerTargetPage;
    }

    @Override
    public void exportTarget(CustomerTargetSearchDTO customerTargetSearchDTO, HttpServletResponse response) {
        String quarterCode = customerTargetSearchDTO.getQuarterCode();
        if (StrUtil.isBlank(quarterCode)) {
            throw new BusinessException(McnErrorCode.PLEASE_CHOOSE_QUARTER_CODE);
        }
        String[] splitQuarterCode = quarterCode.split("Q");
        String chooseYear = splitQuarterCode[0];
        customerTargetSearchDTO.setChoosedYear(chooseYear);

        List<CusTargetExportTotalVO> totalExportList = new ArrayList<>();
        List<CustomerTargetExportVO> exportList = new ArrayList<>();
        /**
         * 如果有客户名称和客户负责人名称的模糊筛选，则获取对应模糊查询结果的客户id集合
         */
        if (StrUtil.isNotBlank(customerTargetSearchDTO.getCustomerName()) || StrUtil.isNotBlank(customerTargetSearchDTO.getCustomerHeadName())) {
            McnCustomerSearchDTO mcnCustomerSearchDTO = new McnCustomerSearchDTO();
            mcnCustomerSearchDTO.setCustomerName(customerTargetSearchDTO.getCustomerName());
            mcnCustomerSearchDTO.setCustomerHeadName(customerTargetSearchDTO.getCustomerHeadName());
            List<BaseCustomer> customerList = baseInfoClient.searchMcnCustomer(mcnCustomerSearchDTO).getObj();
            if (CollectionUtil.isEmpty(customerList)) {
                return;
            }
            customerTargetSearchDTO.setCustomerIds(customerList.stream().map(BaseCustomer::getCustomerId).collect(Collectors.toList()));
        }

        /**
         * 查询原始数据
         */
        customerTargetSearchDTO.setAlias("ct.");
        List<CusBasicExportVO> cusBasicExport = baseMapper.exportTarget(customerTargetSearchDTO);
        if (CollectionUtil.isNotEmpty(cusBasicExport)) {

            /**
             * 设置目标金额
             */
            setTargetAmount(exportList, cusBasicExport, quarterCode);

            /**
             * 设置本季度个人销售额、本季度客户销售、客户目标达成率
             */
            setSaleAmount(exportList, quarterCode);

            /**
             * 设置商务、部门、客户名称
             */
            setCustomerInfo(exportList);

            /**
             * 设置客户负责人的部门信息
             */
            setDepartmentInfo(exportList);

            /**
             * 获取最终导出数据
             */
            getTotalExportList(totalExportList, exportList);
        }
        try {
            customAllExcelName(chooseYear);
            ExcelUtils.exportExcel(totalExportList, quarterCode + "重点客户报表", CusTargetExportTotalVO.class, quarterCode + "重点客户报表.xlsx", response);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    private void getTotalExportList(List<CusTargetExportTotalVO> totalExportList, List<CustomerTargetExportVO> exportList) {
        /**
         * 有客户负责人的按客户负责人分组
         */
        List<CustomerTargetExportVO> hasHeadExportList = exportList.stream().filter(o -> o.getCustomerHeadName() != null && StrUtil.isNotBlank(o.getCustomerHeadDepartmentName())).sorted(Comparator.comparing(CustomerTargetExportVO::getCustomerHeadName)).sorted(Comparator.comparing(CustomerTargetExportVO::getCustomerHeadDepartmentName)).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(hasHeadExportList)) {
            Map<Long, List<CustomerTargetExportVO>> groupingByHeadIdMap = hasHeadExportList.stream().collect(Collectors.groupingBy(CustomerTargetExportVO::getCustomerHeadId));
            for (Map.Entry<Long, List<CustomerTargetExportVO>> entry : groupingByHeadIdMap.entrySet()) {
                CusTargetExportTotalVO cusTargetExportTotal = new CusTargetExportTotalVO();
                CustomerTargetExportVO firstCustomerTargetExport = entry.getValue().get(0);
                cusTargetExportTotal.setCustomerHeadId(firstCustomerTargetExport.getCustomerHeadId());
                cusTargetExportTotal.setCustomerHeadName(firstCustomerTargetExport.getCustomerHeadName());
                cusTargetExportTotal.setCustomerHeadDepartmentId(firstCustomerTargetExport.getCustomerHeadDepartmentId());
                cusTargetExportTotal.setCustomerHeadDepartmentName(firstCustomerTargetExport.getCustomerHeadDepartmentName());
                cusTargetExportTotal.setCustomerTargetExportList(entry.getValue());
                totalExportList.add(cusTargetExportTotal);
            }
        }
        /**
         * 无客户负责人直接写入excel
         */
        List<CustomerTargetExportVO> noHeadExportList = exportList.stream().filter(o -> o.getCustomerHeadName() == null || StrUtil.isBlank(o.getCustomerHeadDepartmentName())).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(noHeadExportList)) {
            for (CustomerTargetExportVO customerTargetExport : noHeadExportList) {
                CusTargetExportTotalVO cusTargetExportTotal = new CusTargetExportTotalVO();
                cusTargetExportTotal.setCustomerHeadId(customerTargetExport.getCustomerHeadId());
                cusTargetExportTotal.setCustomerHeadName(customerTargetExport.getCustomerHeadName());
                cusTargetExportTotal.setCustomerHeadDepartmentId(customerTargetExport.getCustomerHeadDepartmentId());
                cusTargetExportTotal.setCustomerHeadDepartmentName(customerTargetExport.getCustomerHeadDepartmentName());
                cusTargetExportTotal.setCustomerTargetExportList(Arrays.asList(customerTargetExport));
                totalExportList.add(cusTargetExportTotal);
            }
        }
    }

    private void setTargetAmount(List<CustomerTargetExportVO> exportList, List<CusBasicExportVO> cusBasicExport, String quarterCode) {
        Map<Long, List<CusBasicExportVO>> cusBasicExportMap = cusBasicExport.stream().collect(Collectors.groupingBy(CusBasicExportVO::getTargetCustomerId));
        for (Map.Entry<Long, List<CusBasicExportVO>> entry : cusBasicExportMap.entrySet()) {
            CustomerTargetExportVO customerTargetExport = new CustomerTargetExportVO();
            customerTargetExport.setTargetCustomerId(entry.getKey());
            List<CusBasicExportVO> customerTargetRowList = entry.getValue();
            for (CusBasicExportVO cusBasicExportRow : customerTargetRowList) {
                String quarterCodeRow = cusBasicExportRow.getQuarterCode();
                if (quarterCodeRow.equals(quarterCode)) {
                    customerTargetExport.setId(cusBasicExportRow.getId());
                }
                if (quarterCodeRow.endsWith("1")) {
                    customerTargetExport.setTargetAmountQ1(cusBasicExportRow.getTargetAmount());
                }
                if (quarterCodeRow.endsWith("2")) {
                    customerTargetExport.setTargetAmountQ2(cusBasicExportRow.getTargetAmount());
                }
                if (quarterCodeRow.endsWith("3")) {
                    customerTargetExport.setTargetAmountQ3(cusBasicExportRow.getTargetAmount());
                }
                if (quarterCodeRow.endsWith("4")) {
                    customerTargetExport.setTargetAmountQ3(cusBasicExportRow.getTargetAmount());
                }
            }
            exportList.add(customerTargetExport);
        }
    }

    private void setSaleAmount(List<CustomerTargetExportVO> exportList, String quarterCode) {
        List<Long> targetIds = exportList.stream().map(CustomerTargetExportVO::getId).filter(Objects::nonNull).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(targetIds)) {
            List<CusTargetAmountVO> businessAmount = baseMapper.exportBusinessAmount(quarterCode, targetIds);
            if (CollectionUtil.isNotEmpty(businessAmount)) {
                Map<Long, BigDecimal> businessAmountMap = businessAmount.stream().collect(Collectors.toMap(CusTargetAmountVO::getId, CusTargetAmountVO::getAmount));
                for (CustomerTargetExportVO o : exportList) {
                    if (o.getId() != null) {
                        if (businessAmountMap.containsKey(o.getId())) {
                            o.setBusinessSalesAmount(businessAmountMap.get(o.getId()));
                        }
                    }
                }
            }
            List<CusTargetAmountVO> customerAmount = baseMapper.exportCustomerAmount(quarterCode, targetIds);
            if (CollectionUtil.isNotEmpty(customerAmount)) {
                Map<Long, CusTargetAmountVO> customerAmountMap = customerAmount.stream().collect(Collectors.toMap(CusTargetAmountVO::getId, o -> o));
                exportList.stream().filter(o -> o.getId() != null).filter(o -> customerAmountMap.containsKey(o.getId())).forEach(o -> {
                    o.setCustomerSalesAmount(customerAmountMap.get(o.getId()).getAmount());
                    BigDecimal targetReachRate = customerAmountMap.get(o.getId()).getTargetReachRate();
                    o.setCustomerReachRate(targetReachRate.multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP));
                });
            }
        }
    }

    private void setCustomerInfo(List<CustomerTargetExportVO> exportList) {
        List<Long> customerIds = exportList.stream().map(CustomerTargetExportVO::getTargetCustomerId).collect(Collectors.toList());
        Map<Long, BaseCustomer> baseCustomerMap = baseInfoClient.getMcnCustomerByIds(customerIds).getObj();
        for (CustomerTargetExportVO customerTarget : exportList) {
            Long targetCustomerId = customerTarget.getTargetCustomerId();
            if (baseCustomerMap.containsKey(targetCustomerId)) {
                BaseCustomer baseCustomer = baseCustomerMap.get(targetCustomerId);
                customerTarget.setTargetCustomerName(baseCustomer.getCustomerNameC());
                customerTarget.setCustomerHeadId(baseCustomer.getCustomerHeadId());
                customerTarget.setCustomerHeadName(baseCustomer.getCustomerHeadName());
            }
        }
    }

    private void setDepartmentInfo(List<CustomerTargetExportVO> exportList) {
        List<Long> customerHeadIds = exportList.stream().map(CustomerTargetExportVO::getCustomerHeadId).distinct().collect(Collectors.toList());
        List<SUserVo> userHeandList = privilegeClient.getDepartmentByUserIds(customerHeadIds).getObj();
        Map<Long, SUserVo> userHeadMap = userHeandList.stream().collect(Collectors.toMap(SUserVo::getUserId, o -> o));
        for (CustomerTargetExportVO customerTarget : exportList) {
            Long customerHeadId = customerTarget.getCustomerHeadId();
            if (userHeadMap.containsKey(customerHeadId)) {
                SUserVo sUserVo = userHeadMap.get(customerHeadId);
                customerTarget.setCustomerHeadDepartmentId(sUserVo.getDepartmentId());
                customerTarget.setCustomerHeadDepartmentName(sUserVo.getDepartmentName());
            }
        }
    }

    /**
     * 动态修改导出季度目标销售额的年份
     */
    private void customAllExcelName(String chooseYear) throws Exception {
        customSingleExcelName("targetAmountQ1", chooseYear, "Q1目标金额");
        customSingleExcelName("targetAmountQ2", chooseYear, "Q2目标金额");
        customSingleExcelName("targetAmountQ3", chooseYear, "Q3目标金额");
        customSingleExcelName("targetAmountQ4", chooseYear, "Q4目标金额");
    }

    private void customSingleExcelName(String fieldName, String chooseYear, String excelName) throws Exception {
        Field targetAmountQn = CustomerTargetExportVO.class.getDeclaredField(fieldName);
        Excel excel = targetAmountQn.getAnnotation(Excel.class);
        if (null != excel) {
            InvocationHandler invocationHandler = Proxy.getInvocationHandler(excel);
            Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
            memberValues.setAccessible(true);
            Map<String, Object> memberValuesValue = (Map<String, Object>) memberValues.get(invocationHandler);
            memberValuesValue.put("name", chooseYear + excelName);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateQuarterSales() {
        /** 更新客户目标的季度销售金额
         * 取收入合同的创建时间在该季度时间范围内，
         * 单据状态为【审批通过、审批中】状态的所有收入合同的【商务确认合同金额】总和，作为季度销售额保存落库
         */
        baseMapper.updateQuarterSales();

        /**
         * 更新目标达成率=季度销售额/目标金额
         */
        baseMapper.updateTargetReachRate();
    }

    @Override
    public Page<QuarterTargetPageVO> quarterTargetPage(McnPage<QuarterTargetPageVO> mcnPage, Long customerId) {
        if (customerId == null) {
            throw new BusinessException(McnErrorCode.PLEASE_CHOOSE_CUSTOMER);
        }
        Page<QuarterTargetPageVO> quarterTargetPage = baseMapper.quarterTargetPage(mcnPage, customerId);
        List<QuarterTargetPageVO> quarterTargetList = quarterTargetPage.getRecords();
        if (CollectionUtil.isNotEmpty(quarterTargetList)) {
            /**
             * 查询客户信息
             */
            List<Long> customerIds = quarterTargetList.stream().map(QuarterTargetPageVO::getTargetCustomerId).distinct().collect(Collectors.toList());
            Map<Long, BaseCustomer> baseCustomerMap = baseInfoClient.getMcnCustomerByIds(customerIds).getObj();
            for (QuarterTargetPageVO customerTarget : quarterTargetList) {
                Long targetCustomerId = customerTarget.getTargetCustomerId();
                if (baseCustomerMap.containsKey(targetCustomerId)) {
                    BaseCustomer baseCustomer = baseCustomerMap.get(targetCustomerId);
                    customerTarget.setTargetCustomerName(baseCustomer.getCustomerNameC());
                }
            }
        }
        return quarterTargetPage;
    }

    @Override
    public String excelImport(MultipartFile multipartFile) {
        List<CustomerTargetImportDTO> customerTargetImportList = new ArrayList<>();
        try {
            customerTargetImportList = ExcelUtils.importExcel(multipartFile, CustomerTargetImportDTO.class);
        } catch (Exception e) {
            throw new BusinessException(McnErrorCode.IMPORT_EXCEL_FAILED);
        }
        if (CollectionUtil.isEmpty(customerTargetImportList)) {
            throw new BusinessException(McnErrorCode.IMPORT_CONTENT_EMPTY);
        }
        List<CustomerTargetImportDTO> notEmptyList =
                customerTargetImportList.stream().filter(o -> StrUtil.isNotBlank(o.getQuarterCode()) || StrUtil.isNotBlank(o.getCustomerName()) || StrUtil.isNotBlank(o.getTargetAmount())).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(notEmptyList)) {
            throw new BusinessException(McnErrorCode.IMPORT_TEMPLATE_WRONG);
        }
        String fileId = verifyImportParam(customerTargetImportList);
        if (StrUtil.isBlank(fileId)) {
            /**
             * 保存客户目标
             */
            saveExcelContent(customerTargetImportList);
            return "";
        }
        return fileId;
    }

    @Override
    public void excelDownload(HttpServletResponse response, String fileId) {
        List<CustomerTargetOutputDTO> outputList = (List<CustomerTargetOutputDTO>) redisTemplate.opsForValue().get(fileId);
        if (CollectionUtil.isEmpty(outputList)) {
            throw new BusinessException(McnErrorCode.EXPORT_HAS_NO_DATA);
        }
        try {
            ExcelUtils.exportExcel(outputList, "客户目标上传失败原因", CustomerTargetOutputDTO.class, "客户目标上传失败原因.xlsx", response);
            redisTemplate.delete(fileId);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    private String verifyImportParam(List<CustomerTargetImportDTO> customerTargetImportList) {
        List<CustomerTargetOutputDTO> outputList = new ArrayList<>();
        for (CustomerTargetImportDTO customerTargetImportDTO : customerTargetImportList) {
            boolean allParamEmpty = StrUtil.isBlank(customerTargetImportDTO.getCustomerName()) &&
                    StrUtil.isBlank(customerTargetImportDTO.getQuarterCode()) &&
                    StrUtil.isBlank(customerTargetImportDTO.getTargetAmount());
            if (allParamEmpty) {
                continue;
            }
            StringBuffer failedReason = new StringBuffer();
            CustomerTargetOutputDTO customerTargetOutputDTO = new CustomerTargetOutputDTO();
            BeanUtils.copyProperties(customerTargetImportDTO, customerTargetOutputDTO);
            boolean anyParamEmpty = StrUtil.isBlank(customerTargetImportDTO.getCustomerName()) ||
                    StrUtil.isBlank(customerTargetImportDTO.getQuarterCode()) ||
                    StrUtil.isBlank(customerTargetImportDTO.getTargetAmount());
            if (anyParamEmpty) {
                failedReason.append("客户名称、季度编号、目标金额都是必填项，");
            }
            if (StrUtil.isNotBlank(customerTargetImportDTO.getCustomerName())) {
                BaseCustomer baseCustomer = new BaseCustomer();
                baseCustomer.setCustomerNameC(customerTargetImportDTO.getCustomerName());
                baseCustomer.setCustomerStatus(0);
                baseCustomer.setCustomerType(10);
                List<BaseCustomerDetailVO> customerList =
                        baseInfoClient.selectCustomer(baseCustomer).getObj();
                if (customerList.size() == 0) {
                    failedReason.append("客户名称有误，");
                }
            }
            if (StrUtil.isNotBlank(customerTargetImportDTO.getQuarterCode())) {
                boolean matchedQuarterCode = ReUtil.isMatch("\\d{4}[Q-Q][1234]", customerTargetImportDTO.getQuarterCode());
                if (!matchedQuarterCode) {
                    failedReason.append("季度编号错误，");
                }
            }
            if (StrUtil.isNotBlank(customerTargetImportDTO.getTargetAmount())) {
                String targetAmount = customerTargetImportDTO.getTargetAmount();
                boolean endWithW = (targetAmount.endsWith("W") || targetAmount.endsWith("w"));
                if (!endWithW) {
                    failedReason.append("目标金额缺少单位W，");
                }
                String amountNumber = "";
                if (endWithW) {
                    amountNumber = targetAmount.substring(0, targetAmount.length() - 1);
                } else {
                    amountNumber = targetAmount;
                }
                boolean matchedTargetAmount = ReUtil.isMatch("0\\.([1-9]|\\d[1-9])$|^[1-9]\\d{0,20}\\.\\d{0,1}$|^[1-9]\\d{0,8}",
                        amountNumber);
                if (!matchedTargetAmount) {
                    failedReason.append("目标金额仅允许输入大于0且保留一位小数的数据，");
                }
            }
            if (failedReason.toString().endsWith("，")) {
                String reason = failedReason.substring(0, failedReason.length() - 1);
                customerTargetOutputDTO.setFailedReason(reason);
            }
            outputList.add(customerTargetOutputDTO);
        }
        List<CustomerTargetOutputDTO> errorList = outputList.stream().filter(customerTargetOutputDTO -> StrUtil.isNotBlank(customerTargetOutputDTO.getFailedReason())).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(errorList)) {
            /**
             * 上传错误Excel
             * 将包含错误原因的输出内容存在redis，方便用户下载错误原因是将其导出成Excel
             */
            String fileId = CUSTOMER_TARGET_PREFIX + UUID.randomUUID();
            redisTemplate.opsForValue().set(fileId, outputList, 30, TimeUnit.DAYS);
            return fileId;
        }
        return "";
    }

    private void verifyInsertParam(List<CustomerTargetDTO> customerTargetList) {
        if (CollectionUtil.isEmpty(customerTargetList)) {
            throw new BusinessException(McnErrorCode.PARAM_ERROR);
        }
        int distinctSize = customerTargetList.stream().map(CustomerTargetDTO::getTargetCustomerId)
                .distinct().collect(Collectors.toList()).size();
        if (customerTargetList.size() > distinctSize) {
            throw new BusinessException(McnErrorCode.CUSTOMER_CAN_NOT_REPEAT);
        }
        customerTargetList.forEach(d -> {
            boolean paramError = d.getTargetCustomerId() == null
                    || d.getTargetAmount() == null || StrUtil.isBlank(d.getQuarterCode());
            if (paramError) {
                throw new BusinessException(McnErrorCode.PARAM_ERROR);
            }
        });
    }

    private void verifyTargetCount(List<CustomerTargetDTO> customerTargetList) {
        for (CustomerTargetDTO customerTargetDTO : customerTargetList) {
            LambdaQueryWrapper<CustomerTarget> queryWrapper = Wrappers.lambdaQuery(CustomerTarget.class)
                    .eq(CustomerTarget::getQuarterCode, customerTargetDTO.getQuarterCode())
                    .eq(CustomerTarget::getTargetCustomerId, customerTargetDTO.getTargetCustomerId())
                    .eq(CustomerTarget::getIsDelete, Boolean.FALSE);
            Integer existCount = baseMapper.selectCount(queryWrapper);
            if (existCount > 0) {
                throw new BusinessException(McnErrorCode.CUSTOMER_TARGET_EXIST);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveExcelContent(List<CustomerTargetImportDTO> customerTargetImportList) {
        UserVO user = UserVoContextHolder.getUserVo();
        List<CustomerTarget> customerTargetAddList = new ArrayList<>();
        /**
         * 通过客户名称获取客户id
         */
        List<String> customerNameList = customerTargetImportList.stream().map(CustomerTargetImportDTO::getCustomerName).collect(Collectors.toList());
        Map<String, Long> customerIdMap = baseInfoClient.getCustomerIdByName(customerNameList).getObj();

        /**
         * 查询传入的客户中已存在重点客户目标的
         */
        List<Long> customerIds = new ArrayList<Long>(customerIdMap.values());
        List<CustomerTarget> existCustomerTargets = getByCustomerIds(customerIds);
        List<Long> existCustomerIds = new ArrayList<>();
        Map<String, List<CustomerTarget>> existCustomerMap = new HashMap<>(16);
        if (CollectionUtil.isNotEmpty(existCustomerTargets)) {
            existCustomerIds = existCustomerTargets.stream().map(CustomerTarget::getTargetCustomerId).collect(Collectors.toList());
            existCustomerMap = existCustomerTargets.stream().collect(Collectors.groupingBy(a -> a.getTargetCustomerId() + ":" + a.getQuarterCode()));
        }
        for (CustomerTargetImportDTO c : customerTargetImportList) {
            boolean allParamEmpty = StrUtil.isBlank(c.getCustomerName()) &&
                    StrUtil.isBlank(c.getQuarterCode()) &&
                    StrUtil.isBlank(c.getTargetAmount());
            if (allParamEmpty) {
                continue;
            }
            String targetAmountString = c.getTargetAmount();
            BigDecimal targetAmount = new BigDecimal(targetAmountString.substring(0, targetAmountString.length() - 1));
            BigDecimal realTargetAmount = targetAmount.multiply(BigDecimal.valueOf(10000));
            Long targetCustomerId = customerIdMap.get(c.getCustomerName());
            if (existCustomerIds.contains(targetCustomerId) && existCustomerMap.containsKey(targetCustomerId + ":" + c.getQuarterCode())) {
                List<CustomerTarget> customerTargets = existCustomerMap.get(targetCustomerId + ":" + c.getQuarterCode());
                CustomerTarget customerTarget = customerTargets.get(0);
                customerTarget.setTargetAmount(realTargetAmount);
                baseMapper.updateById(customerTarget);
            } else {
                CustomerTarget customerTarget = new CustomerTarget();
                customerTarget.setQuarterCode(c.getQuarterCode());
                customerTarget.setTargetAmount(realTargetAmount);
                if (customerIdMap.containsKey(c.getCustomerName())) {
                    customerTarget.setTargetCustomerId(customerIdMap.get(c.getCustomerName()));
                }
                customerTargetAddList.add(customerTarget);
            }
        }
        if (CollectionUtil.isNotEmpty(customerTargetAddList)) {
            baseMapper.insertBatch(customerTargetAddList);
        }
    }

    private List<CustomerTarget> getByCustomerIds(List<Long> customerIds) {
        return baseMapper.selectList(Wrappers.lambdaQuery(CustomerTarget.class)
                .in(CustomerTarget::getTargetCustomerId, customerIds)
                .eq(CustomerTarget::getIsDelete, Boolean.FALSE));
    }
}
